home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
NOVA - For the NeXT Workstation
/
NOVA - For the NeXT Workstation.iso
/
SourceCode
/
AdobeExamples
/
NX_ImportAdv
/
DocView.m
< prev
next >
Wrap
Text File
|
1992-12-19
|
10KB
|
358 lines
/*
* (a) (C) 1990 by Adobe Systems Incorporated. All rights reserved.
*
* (b) If this Sample Code is distributed as part of the Display PostScript
* System Software Development Kit from Adobe Systems Incorporated,
* then this copy is designated as Development Software and its use is
* subject to the terms of the License Agreement attached to such Kit.
*
* (c) If this Sample Code is distributed independently, then the following
* terms apply:
*
* (d) This file may be freely copied and redistributed as long as:
* 1) Parts (a), (d), (e) and (f) continue to be included in the file,
* 2) If the file has been modified in any way, a notice of such
* modification is conspicuously indicated.
*
* (e) PostScript, Display PostScript, and Adobe are registered trademarks of
* Adobe Systems Incorporated.
*
* (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
* CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
* AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
* ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
* OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
* WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
* WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
* DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
* OF THIRD PARTY RIGHTS.
*/
/*
* DocView.m
*
* This class handles the scaling of the drawing view. It repositions
* The drawing view within itself if the drawing view is smaller than the
* size of the clip view. The size of the doc view is:
* MAX(clip view frame, drawing view frame).
*
* This class is used in several of the other Display PostScript programs.
* Some of the methods may be different as the class became more and
* more refined but the general operation remains the same.
*
* Version: 2.0
* Author: Ken Fromm
*/
#import "DocView.h"
#import "ImportApp.h"
#import <appkit/Cursor.h>
#import <appkit/Matrix.h>
#import <appkit/ScrollView.h>
#import <dpsclient/wraps.h>
#import <appkit/nextstd.h>
@implementation DocView
/*
* Since there is only one subview its easier to keep track of it as an
* instance variable rather than in the subview list.
*/
- setDrawView:newView
{
id oldView;
oldView = drawviewId;
[oldView removeFromSuperview];
[self addSubview:newView];
drawviewId = newView;
return oldView;
}
- drawView
{
return drawviewId;
}
- setScale:(float)value
{
scale = value;
return self;
}
- (float) scale
{
return scale;
}
/*
* Check whether the frame of the drawingview is in the rectangle passed in.
* If drop is true, then include the linewidth and the drop shadow as part of the
* drawingview frame.
*/
- getDrawViewInRect:(const NXRect *) aRect withDrop:(BOOL) drop
{
id aView = NULL;
NXRect viewRect, dropRect;
[drawviewId getFrame:&viewRect];
if (drop)
{
dropRect = viewRect;
NXOffsetRect(&dropRect, rint(OFFSET * scale), rint(-OFFSET * scale));
NXOffsetRect(&viewRect, rint(LINEWIDTH/2 * scale), rint(LINEWIDTH/2 * scale));
NXUnionRect(&dropRect, &viewRect);
}
if (NXIntersectsRect(aRect, &viewRect))
aView = drawviewId;
return aView;
}
/*
* Sizes the drawing view from the old scale to the newscale.
* The frame of the view is used instead of the bounds because
* the bound will always be the same whereas the frame will
* provide the size in default coordinates.
*/
- sizeView:viewId withScale:(float) newscale
{
float scalefactor, sizewidth, sizeheight;
NXRect viewFrame;
[viewId getFrame:&viewFrame];
scalefactor = newscale/scale;
sizewidth = viewFrame.size.width*scalefactor;
sizeheight = viewFrame.size.height*scalefactor;
[viewId sizeTo:rint(sizewidth) :rint(sizeheight)];
return self;
}
/*
* Scales the drawing view from the old scale to the new scale.
* The scale method is relative so we use the ratio
* of the old scale to the new scale to obtain the scaling factor.
*/
- scaleView:viewId withScale:(float) newscale
{
float scalefactor;
scalefactor = newscale/scale;
[viewId scale:scalefactor :scalefactor];
return self;
}
/*
* Place the view passed in in the center of the doc view
* if it is smaller than the size of the ClipView. Two passes are made
* through the loop because adding or removing a horizontal or
* vertical scrollbar will affect the size of the remaining dimension .
*/
- placeView:viewId
{
BOOL vert = NO, horiz = NO, done = NO;
int passes = 0, border_type;
float margin;
NXSize contSize, newSize, insetSize, delta;
NXRect viewFrame, scrollFrame;
margin = 4 * OFFSET * scale;
[viewId getFrame:&viewFrame];
[[superview superview] getFrame:&scrollFrame];
border_type = [[superview superview] borderType];
while (!done && ++passes <= 2)
{
[ScrollView getContentSize:&contSize forFrameSize:&scrollFrame.size
horizScroller:horiz vertScroller:vert borderType:border_type];
newSize.width = MAX(viewFrame.size.width, contSize.width);
newSize.height = MAX(viewFrame.size.height, contSize.height);
delta.width = newSize.width - viewFrame.size.width;
delta.height = newSize.height - viewFrame.size.height;
if (delta.width != 0.0 || delta.height != 0.0)
{
if (delta.width < margin)
newSize.width += margin - delta.width;
if (delta.height < margin)
newSize.height += margin - delta.height;
}
horiz = (newSize.width != contSize.width);
vert = (newSize.height != contSize.height);
if ((horiz && vert) || (!horiz && !vert))
done = YES;
else
done = NO;
}
[self sizeTo:newSize.width :newSize.height];
insetSize.width = floor((newSize.width - viewFrame.size.width)/2);
insetSize.height = floor((newSize.height - viewFrame.size.height)/2);
[viewId moveTo:insetSize.width :insetSize.height];
if (insetSize.width != 0 || insetSize.height != 0)
[viewId setClipping:YES];
else
[viewId setClipping:NO];
if (horiz)
[[superview superview] setHorizScrollerRequired:YES];
else
[[superview superview] setHorizScrollerRequired:NO];
if (vert)
[[superview superview] setVertScrollerRequired:YES];
else
[[superview superview] setVertScrollerRequired:NO];
return self;
}
/*
* Scales the view to the tag of the selected matrix cell and then
* scrolls to the point. The point is in window coordinates so
* it must be converted to the drawing view coordinates in order
* to position it in the same relative place in the view.
*/
- scaleDrawView:hitView withEvent:(NXEvent *) event;
{
float newscale;
NXPoint viewPt;
[window invalidateCursorRectsForView:self];
if ((event->flags & NX_ALTERNATEMASK) == NX_ALTERNATEMASK)
newscale = scale / INCSCALE;
else
newscale = scale * INCSCALE;
if (hitView && newscale >= MINSCALE && newscale <= MAXSCALE)
{
viewPt = event->location;
[self convertPoint:&viewPt fromView:nil];
[self convertPoint:&viewPt toView:hitView];
[window disableDisplay];
/* Size and then scale the drawing view. The frame of the */
/* drawing view must reflect the changed size. Scaling */
/* alone will not change the frame. */
[self sizeView:hitView withScale:newscale];
[self scaleView:hitView withScale:newscale];
[self setScale:newscale];
[self placeView:hitView];
[self scrollPoint:&viewPt inView:hitView to:&event->location];
[window reenableDisplay];
[[window contentView] display];
}
else
[NXApp clearOperation];
return self;
}
/*
* Use the point location relative to the window versus the point relative
* to the drawing view (before the scale) to determine where to scroll
* the drawing view. We want the same location in the drawing view to
* appear where the mouse downed occurred. The window coordinates
* are used and then adjusted by the position of the scrolling frame
* because the presence or absence of scrollbars throws the use
* of the doc views coordinates awry.
*/
- scrollPoint:(const NXPoint *) aPt inView:hitView to:(const NXPoint *) windowPt
{
NXPoint viewPt;
NXSize contSize;
NXRect viewFrame, visRect, scrollFrame;
[[superview superview] getContentSize:&contSize];
[hitView getFrame:&viewFrame];
if (viewFrame.size.width > contSize.width || viewFrame.size.height > contSize.height)
{
viewPt = *aPt;
[self convertPoint:&viewPt fromView:hitView];
[self getVisibleRect:&visRect];
[[superview superview] getFrame:&scrollFrame];
if (viewFrame.size.width > contSize.width)
viewPt.x -= windowPt->x - (scrollFrame.origin.x +scrollFrame.size.width -
visRect.size.width);
if (viewFrame.size.height > contSize.height)
viewPt.y -= windowPt->y - (scrollFrame.origin.y + scrollFrame.size.height -
visRect.size.height);
[self scrollPoint:&viewPt];
}
return self;
}
/*
* This drawSelf method draws a border around the drawing view as well as a
* drop shadow. This is only done if it will be visible however. We tell if it is visible
* if the rectangle passed in is not contained entirely within drawingView frame.
*/
- drawSelf:(NXRect *)r :(int) count
{
id visView;
NXRect drawRect, dropRect, bRect, xRect, yRect;
visView = [self getDrawViewInRect:r withDrop:YES];
if (visView)
{
/* Calculate the rectangle of the draw view plus its drop shadow. */
[visView getFrame:&drawRect];
dropRect = bRect = drawRect;
NXOffsetRect(&bRect, -rint(LINEWIDTH/2 * scale), -rint(LINEWIDTH/2 * scale));
NXOffsetRect(&dropRect, rint(OFFSET * scale), rint(-OFFSET * scale));
NXUnionRect(&dropRect, &bRect);
if (!NXContainsRect(&bRect, r))
{
bRect = xRect = yRect = dropRect;
NXIntersectionRect(&drawRect, &bRect);
NXDivideRect(&xRect, &dropRect, bRect.size.width, 0);
NXDivideRect(&yRect, &dropRect, bRect.size.height, 3);
PSgsave();
PSsetgray(NX_BLACK);
PSrectclip(r->origin.x, r->origin.y, r->size.width, r->size.height);
PSrectfill(xRect.origin.x, xRect.origin.y,
xRect.size.width, xRect.size.height);
PSrectfill(yRect.origin.x, yRect.origin.y,
yRect.size.width, yRect.size.height);
PSsetlinewidth(LINEWIDTH * scale);
PSrectstroke(drawRect.origin.x, drawRect.origin.y,
drawRect.size.width, drawRect.size.height);
PSgrestore();
}
}
return self;
}
@end